﻿using SimpleTerminal.Common;
using SimpleTerminal.Library;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Win32;

namespace SimpleTerminal
{
    public partial class Shadow : Form
    {
        public Shadow()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            InitializeComponent();
            FormBorderStyle = FormBorderStyle.None;
        }
        protected override bool ShowWithoutActivation
        {
            get { return true; }
        }
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cParms = base.CreateParams;
                cParms.ExStyle |= 0x00080000; // WS_EX_LAYERED
                                              // cParms.ExStyle |= User32.WS_EX_TRANSPARENT;
                return cParms;
            }
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {

                case User32.WM_ACTIVATE:
                    // if (CompositionEnabled())
                    //  {
                    int v = 1;
                    User32.DwmSetWindowAttribute(Handle, 2, ref v, 4);
                    // }
                    break;
                case User32.WM_WINDOWPOSCHANGING:

                    //  Point p = PointToScreen(new Point(tagWINDOWPOS.x, tagWINDOWPOS.y));
                    //  Point p = new Point(tagWINDOWPOS.x, tagWINDOWPOS.y);

                    User32.TagWINDOWPOS tagWINDOWPOS =
                                              (User32.TagWINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(User32.TagWINDOWPOS));

                    if (((tagWINDOWPOS.flags & User32.SWP_NOSIZE) != User32.SWP_NOSIZE))
                    {

                        DrawShadow(tagWINDOWPOS.x, tagWINDOWPOS.y, tagWINDOWPOS.cx - 1, tagWINDOWPOS.cy - 1, resizeBegin);

                    }
                    //   Marshal.
                    /*
                    if (m.WParam != IntPtr.Zero)
                    {
                        User32.TagNCCALCSIZE_PARAMS tagNCCALCSIZE_PARAMS =
                                                (User32.TagNCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(User32.TagNCCALCSIZE_PARAMS));
                        DrawShadow(
                            tagNCCALCSIZE_PARAMS.rgrc[0].left,
                            tagNCCALCSIZE_PARAMS.rgrc[0].top,
                            tagNCCALCSIZE_PARAMS.rgrc[0].right - tagNCCALCSIZE_PARAMS.rgrc[0].left,
                            tagNCCALCSIZE_PARAMS.rgrc[0].bottom - tagNCCALCSIZE_PARAMS.rgrc[0].top
                            );
                    }*/

                    break;
                case 0x0084:
                    //     User32.SendMessage(Owner.Handle, m.Msg, m.WParam, m.LParam);
                    //     return;
                    break;
                case 0x231:
                    User32.SendMessage(Owner.Handle, 231, 0, 0);

                    break;
                case 0x232:
                    User32.SendMessage(Owner.Handle, 232, 0, 0);
                    break;
                case 0xb:
                    User32.SendMessage(Owner.Handle, 0xb, m.WParam, m.LParam);
                    break;
            }
            base.WndProc(ref m);

            //  Log.Debug("xxx", m.ToString());
        }

        public Shadow(Form parent) : base()
        {
            Location = new Point(parent.Location.X - PaddingSize, parent.Location.Y - PaddingSize);

            Size = new Size(parent.Width + PaddingSize * 2, parent.Height + PaddingSize * 2);
            MinimumSize = new Size(parent.MinimumSize.Width + PaddingSize * 2,
                parent.MinimumSize.Height + PaddingSize * 2);
            parent.LocationChanged += delegate
            {
                if (!resizeBegin)
                    Location = new Point(parent.Location.X - PaddingSize, parent.Location.Y - PaddingSize);
            };
            parent.SizeChanged += delegate
            {
                if (!resizeBegin)
                {
                    //     Location = new Point(parent.Location.X - BorderSize, parent.Location.Y - BorderSize);
                    Size = new Size(parent.Width + PaddingSize * 2, parent.Height + PaddingSize * 2);

                }

            };
        }

        public void UpdateLocation()
        {
            Location = new Point(Owner.Location.X - PaddingSize, Owner.Location.Y - PaddingSize);
        }


        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            DrawShadow();
        }

        bool resizeBegin = false;
        protected override void OnResizeBegin(EventArgs e)
        {
            base.OnResizeBegin(e);
            resizeBegin = true;
            Console.WriteLine("OnResizeBegin");
        }

        protected override void OnResizeEnd(EventArgs e)
        {
            base.OnResizeEnd(e);
#if !HIDE
            if (Owner != null)
            {
                //Owner.Size = new Size(Width - BorderSize * 2, Height - BorderSize * 2);
                // Owner.Location = new Point(Left + BorderSize, Top + BorderSize);
                User32.SetWindowPos(Owner.Handle,
                                     IntPtr.Zero,
                                     Left + BorderSize, Top + BorderSize,
                                    Width - BorderSize * 2, Height - BorderSize * 2,
                                    User32.SWP_NOCOPYBITS);
                // */
            }
            resizeBegin = false;

            DrawShadow();
#endif
        }

        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);
            //if (resizeBegin)
            // {
            //    DrawShadow();
            // }
        }


        protected override void OnSizeChanged(EventArgs e)
        {
            //resizeBegin = false;
            base.OnSizeChanged(e);
#if HIDE
            if (Owner != null)
            {

                User32.SetWindowPos(Owner.Handle,
                                     IntPtr.Zero,
                                     Left + BorderSize, Top + BorderSize,
                                     Width - BorderSize * 2, Height - BorderSize * 2,
                                     User32.SWP_FRAMECHANGED | User32.SWP_NOZORDER);
                // */
            }
#endif
            //  DrawShadow();
            //   Owner.Size = new Size(Width - 16, Height - 16);
            //Console.WriteLine(Location.ToString());
            //Console.WriteLine(Size.ToString());

        }

        public static void DrawRoundRectangle(Graphics g, Pen pen, Rectangle rect, int cornerRadius)
        {
            using (GraphicsPath path = CreateRoundedRectanglePath(rect, cornerRadius))
            {
                g.DrawPath(pen, path);
            }
        }
        public static void FillRoundRectangle(Graphics g, Brush brush, Rectangle rect, int cornerRadius)
        {
            using (GraphicsPath path = CreateRoundedRectanglePath(rect, cornerRadius))
            {
                g.FillPath(brush, path);
            }
        }
        internal static GraphicsPath CreateRoundedRectanglePath(Rectangle rect, int cornerRadius)
        {
            GraphicsPath roundedRect = new GraphicsPath();
            roundedRect.StartFigure();
            roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
            roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
            roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
            roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom);
            roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
            roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
            roundedRect.CloseFigure();
            return roundedRect;
        }
        internal void DrawShadow()
        {
            DrawShadow(Left, Top, Width, Height, false);
        }

        int BorderSize = 8;
        public int PaddingSize = 8;
        internal void DrawShadow(int x, int y, int width, int height, bool mask)
        {

            Bitmap bitmap = null;
            Graphics g = null;
            try
            {
                bitmap = new Bitmap(width, height);
                g = Graphics.FromImage(bitmap);


                g.SmoothingMode = SmoothingMode.AntiAlias;

                Color c = Color.FromArgb(0, 0, 0, 0);
                Pen p = new Pen(c, 1);
                /*
                LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
                   new Rectangle(0,8,8,height),
                   Color.FromArgb(0,0,0,0),
                   Color.FromArgb(100,0,0,0),
                   LinearGradientMode.Horizontal
                    );*/
                // g.FillRectangle(linearGradientBrush, new Rectangle(0, 8, 8, height));
                int[] ds = new int[8] { 1, 2, 4, 11, 23, 26, 30, 46 };
                for (int i = 0; i < BorderSize; i++)
                {
                    // float d = 30f / 8f  * (i+1);
                    double d = (double)(Math.Tan(Math.PI * 60 / 180) * (1d / BorderSize * (i + 1)));
                    Console.WriteLine(d);
                    int t = (int)(d * 20);
                    Console.WriteLine(t);
                    p.Color = Color.FromArgb(ds[i], c);
                    DrawRoundRectangle(g, p, new Rectangle(i, i, width - (2 * i) - 1, height - (2 * i) - 1), BorderSize - i);
                }
                // g.FillRectangle(SystemBrushes.Control,0,0,Width,height);
                //  using (Pen pen = new Pen(Color.FromArgb(0x33, 0x33, 0x33), 1))
                using (Pen pen = new Pen(Color.FromArgb(0, 0, 0), 1))
                using (SolidBrush solidBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                {
                    g.DrawRectangle(pen, new Rectangle(PaddingSize - 1, PaddingSize - 1, width - (2 * PaddingSize) + 1, height - (2 * PaddingSize) + 1));

                    if (mask && Owner != null)
                    {
                        if (Owner.Width == Width - BorderSize * 2 &&
                          Owner.Height == Height - BorderSize * 2)
                        {

                        }
                        else if (Owner.Width < Width - BorderSize * 2 ||
                           Owner.Height < Height - BorderSize * 2)
                        {
                            g.ExcludeClip(new Rectangle(Owner.Left - x, Owner.Top - y, Owner.Width, Owner.Height));
                            g.FillRectangle(solidBrush, BorderSize - 1,
                                                  BorderSize - 1,
                                                  width - 2 * BorderSize + 1,
                                                  height - 2 * BorderSize + 1);
                        }
                        else
                        {
                            solidBrush.Color = Color.FromArgb(100, 0x32, 0x8c, 0xc9);
                            g.FillRectangle(solidBrush, BorderSize - 1,
                                                  BorderSize - 1,
                                                  width - 2 * BorderSize + 1,
                                                  height - 2 * BorderSize + 1);
                        }


                    }

                }

                SetBits(bitmap, x, y, width, height);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            finally
            {
                g?.Dispose();
                bitmap?.Dispose();
            }
        }


        public void SetBits(Bitmap bitmap, int left, int top, int width, int height)
        {

            IntPtr oldBits = IntPtr.Zero;
            IntPtr screenDC = User32.GetDC(IntPtr.Zero);
            IntPtr hBitmap = IntPtr.Zero;
            IntPtr memDc = User32.CreateCompatibleDC(screenDC);

            try
            {

                User32.TagPOINT topLoc = new User32.TagPOINT
                {
                    x = left,
                    y = top
                    // x = 0,
                    //  y = 0
                };
                User32.TagSIZE bitmapSize = new User32.TagSIZE
                {
                    cx = width,
                    cy = height
                };
                User32.TagPOINT srcLoc = new User32.TagPOINT
                {
                    x = 0,
                    y = 0
                };

                hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
                oldBits = User32.SelectObject(memDc, hBitmap);

                User32.BLENDFUNCTION blend = new User32.BLENDFUNCTION
                {
                    BlendOp = User32.AC_SRC_OVER,
                    SourceConstantAlpha = 255,
                    AlphaFormat = User32.AC_SRC_ALPHA,
                    BlendFlags = 0
                };

                User32.UpdateLayeredWindow(Handle,
                    screenDC, ref topLoc,
                    ref bitmapSize, memDc, ref srcLoc, 0, ref blend, User32.ULW_ALPHA);
            }
            finally
            {
                if (hBitmap != IntPtr.Zero)
                {
                    User32.SelectObject(memDc, oldBits);
                    User32.DeleteObject(hBitmap);
                }
                User32.ReleaseDC(IntPtr.Zero, screenDC);
                User32.DeleteDC(memDc);
            }
        }
        // MainForm mainForm = new MainForm();

        private void Shadow_Load(object sender, EventArgs e)
        {
            //mainForm.Show();
        }
    }
}
